<?php

namespace ApiSdk\TikTokShop\Servers;

use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Config\Repository;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Redis\RedisManager;

class AccessTokenService extends BaseService
{

    /**
     * Notes: 生成授权地址
     * author: lfy
     * Date: 2021/10/11
     * Time: 10:41
     * @param $state
     * @param string $scope
     * @return string
     */
    public function firstAuthAppToken($state, string $scope = ''): string
    {
        return $this->getAuthorizedUrl($state, $scope);
    }

    /**
     * Notes:获取token
     * author: lfy
     * Date: 2021/10/11
     * Time: 10:42
     * @param string $code
     * @param string|null $grant_type
     * @return bool|void
     * @throws GuzzleException
     */
    public function getToken(string $code, string $grant_type = 'authorized_code')
    {
        $this->addApiParam('grant_type', $grant_type);
        $this->addApiParam('auth_code', $code);
        return $this->setAuthBaseUrl()->getTokenData('/api/v2/token/get','GET');
    }

    /**
     * Notes: 刷新token
     * author: lfy
     * Date: 2021/10/11
     * Time: 10:17
     * @param string $refresh_token
     * @return bool|void
     * @throws GuzzleException
     */
    public function refreshToken(string $refresh_token = '')
    {
        $this->addApiParam('grant_type', 'refresh_token');
        $this->addApiParam('refresh_token', $refresh_token);
//        return $this->setAuthBaseUrl()->getTokenData('/api/token/refreshToken');
        return $this->setAuthBaseUrl()->getTokenData('/api/v2/token/refresh','GET');
    }

    /**
     * Notes:   获取商家信息
     * author: lfy
     * Date: 2021/11/22
     * Time: 18:04
     * @return array|bool|void
     * @throws GuzzleException
     */
    public function getAuthorizedShop($shop_id = null)
    {
        if (!empty($shop_id)) $this->addApiParam('shop_id', $shop_id);
        return $this->get('/api/shop/get_authorized_shop');
    }

    public function authorizedShopsV23(){
        return $this->get('/authorization/202309/shops');
    }


    private function _getRedisManager(): RedisManager
    {
        return app(RedisManager::class);
    }

    private function _getAccessTokenKey(string $shopId): string
    {
        return "platform_auth:tiktok:access_token:${shopId}";
    }

    private function _getRefreshTokenKey($shopId): string
    {
        return "platform_auth:tiktok:refresh_token:${shopId}";
    }

    /**
     * Notes: 设置缓存
     * author: lfy
     * Date: 2021/11/19
     * Time: 17:20
     * @param $TokenData
     * @return bool
     */
    public function setAccessTokenCache($tokenData, $keyType = 1): bool
    {
        $redisManager = $this->_getRedisManager();
        try {
            $accessToken        = $tokenData['access_token'];
            $refreshToken       = $tokenData['refresh_token'];
            $expiresIn          = $tokenData['access_token_expire_in'];
            $refreshExpiresIn   = $tokenData['refresh_token_expire_in'];
            $shopId             = $tokenData['shop_id'];
            $userId             = $tokenData['user_id'] ?? 0;
            $id                 = $tokenData['id'] ?? 0;
            $shopName           = $tokenData['shop_name'] ?? $shopId;
            $shopSite           = $tokenData['shop_site'] ?? '';
            $isCb               = $tokenData['is_cb'] ?? 0;
            $isGlobal           = $tokenData['is_global'] ?? 0;
            $shop_code          = $tokenData['shop_code'] ?? '';
            $shop_cipher        = $tokenData['shop_cipher'] ?? '';
            $platform           = $tokenData['platform'] ?? 'TikTok';
            $minRefreshLeftTime = time() + 24 * 3600;//  30 minutes before the token expires
            $expiresIn          -= $minRefreshLeftTime;
            $refreshExpiresIn   -= $minRefreshLeftTime;
            $redisManager->pipeline(function ($pipe) use ($tokenData, $shopId, $accessToken, $expiresIn, $refreshExpiresIn, $refreshToken, $userId, $id, $shopName, $shopSite, $isCb, $isGlobal, $keyType, $shop_code, $shop_cipher, $platform) {
                $keyId          = $keyType == 1 ? $shopId : $id;
                $accessTokenKey = $this->_getAccessTokenKey($keyId);
                $cacheData      = array_merge($tokenData, [
                    'access_token' => $accessToken,
                    'shop_id'      => $shopId,
                    'user_id'      => $userId,
                    'id'           => $id,
                    'shop_name'    => $shopName,
                    'shop_site'    => $shopSite,
                    'is_cb'        => $isCb,
                    'is_global'    => $isGlobal,
                    'shop_code'    => $shop_code,
                    'shop_cipher'  => $shop_cipher,
                    'platform'     => $platform
                ]);
                $pipe->set($accessTokenKey, json_encode($cacheData));
                $pipe->expire($accessTokenKey, $expiresIn);
                $refreshTokenKey = $this->_getRefreshTokenKey($keyId);
                unset($cacheData['access_token']);
                $cacheData['refresh_token'] = $refreshToken;
                $pipe->set($refreshTokenKey, json_encode($cacheData));
                $pipe->expire($refreshTokenKey, $refreshExpiresIn);
            });
            return true;
        } catch (Exception $e) {
            \Log::channel('TikTokServers')->error('设置TikTok AccessToken到缓存异常', ['msg' => $e->getMessage(), 'token_data' => $tokenData]);
            return false;
        }
    }

    /**
     * Notes: 从缓存中获取 AccessToken
     * author: lfy
     * Date: 2021/11/10
     * Time: 16:30
     * @param string $shopId
     * @param string $func
     * @return mixed|string
     * @throws GuzzleException
     */
    public function getAccessTokenBySellerId(string $shopId, $func = '')
    {
        $redisManager   = $this->_getRedisManager();
        $accessTokenKey = $this->_getAccessTokenKey($shopId);
        $accessToken    = $redisManager->get($accessTokenKey);
        // AccessToken 过期
        if (empty($accessToken)) {
            $refreshTokenKey = $this->_getRefreshTokenKey($shopId);
            $refreshToken    = json_decode($redisManager->get($refreshTokenKey), true);
            // RefreshToken 过期
            $tokenData = [];
//            $refreshToken['refresh_token'] = 'M2U1NGU5ZGIwNmVlYmQ3ZGE1YjA0MzVjZTcwZDU1NTRjNDQyY2ZhMDU4YWU0N';
            $tokenData = $this->refreshToken($refreshToken['refresh_token'] ?? '');
//            if (!empty($refreshToken) && isset($refreshToken['refresh_token'])) {
            if (!empty($refreshToken) && isset($tokenData['code']) && $tokenData['code'] == 0) {
                $tokenData                = $tokenData['data'];
                $accessToken              = array_merge($refreshToken, [
                    'access_token' => $tokenData['access_token'] ?? ''
                ]);
                $tokenData['shop_id']     = $refreshToken['shop_id'];
                $tokenData['user_id']     = $refreshToken['user_id'];
                $tokenData['id']          = $refreshToken['id'];
                $tokenData['shop_name']   = $refreshToken['shop_name'];
                $tokenData['shop_site']   = $refreshToken['shop_site'];
                $tokenData['is_global']   = $accessToken['is_global'] ?? 0;
                $tokenData['is_cb']       = $accessToken['is_cb'] ?? 0;
                $tokenData['shop_code']   = $accessToken['shop_code'] ?? '';
                $tokenData['shop_cipher'] = $accessToken['shop_cipher'] ?? '';
                $tokenData['platform'] = $accessToken['platform'] ?? 'TikTok';
                $tokenData                = array_merge($refreshToken, $tokenData);
                $this->setAccessTokenCache($tokenData);
            }
            if (is_callable($func)) $func($tokenData);
        }
        return $accessToken;
    }

    public function getRedisKey($shopId = '*')
    {
        $redisManager   = $this->_getRedisManager();
        $accessTokenKey = $this->_getAccessTokenKey($shopId);
        return $redisManager->keys($accessTokenKey);
    }
}
